home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 9 / Example 9.1 / app.cpp next >
Encoding:
C/C++ Source or Header  |  2006-08-01  |  10.8 KB  |  446 lines

  1. //////////////////////////////////////////////////////////////
  2. // Example 9.1: Unit Example                                //
  3. // Written by: C. Granberg, 2006                            //
  4. //////////////////////////////////////////////////////////////
  5.  
  6. #include <windows.h>
  7. #include <d3dx9.h>
  8. #include "debug.h"
  9. #include "shader.h"
  10. #include "terrain.h"
  11. #include "camera.h"
  12. #include "mouse.h"
  13. #include "unit.h"
  14.  
  15. class APPLICATION
  16. {
  17.     public:
  18.         APPLICATION();
  19.         HRESULT Init(HINSTANCE hInstance, int width, int height, bool windowed);
  20.         HRESULT Update(float deltaTime);
  21.         HRESULT Render();
  22.         void Select();
  23.         int GetUnit();
  24.         HRESULT Cleanup();
  25.         HRESULT Quit();
  26.         DWORD FtoDword(float f){return *((DWORD*)&f);}
  27.         void AddUnits();
  28.  
  29.     private:
  30.         IDirect3DDevice9* m_pDevice; 
  31.         TERRAIN m_terrain;
  32.         CAMERA m_camera;
  33.         MOUSE m_mouse;
  34.         std::vector<UNIT*> m_units;
  35.  
  36.         bool m_areaSelect;
  37.         INTPOINT m_startSelect;
  38.         DWORD m_time;
  39.         int m_fps, m_lastFps;
  40.         HWND m_mainWindow;
  41.         ID3DXFont *m_pFont;
  42.         ID3DXLine *m_pLine;
  43.  
  44.         //Shaders
  45.         SHADER m_unitVS, m_unitPS;
  46.         D3DXHANDLE m_worldHandle, m_viewProjHandle, m_sunHandle, m_teamColHandle;
  47. };
  48.  
  49. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
  50. {
  51.     APPLICATION app;
  52.  
  53.     if(FAILED(app.Init(hInstance, 800, 600, true)))
  54.         return 0;
  55.  
  56.     MSG msg;
  57.     memset(&msg, 0, sizeof(MSG));
  58.     int startTime = timeGetTime(); 
  59.  
  60.     while(msg.message != WM_QUIT)
  61.     {
  62.         if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  63.         {
  64.             ::TranslateMessage(&msg);
  65.             ::DispatchMessage(&msg);
  66.         }
  67.         else
  68.         {    
  69.             int t = timeGetTime();
  70.             float deltaTime = (t - startTime)*0.001f;
  71.  
  72.             app.Update(deltaTime);
  73.             app.Render();
  74.  
  75.             startTime = t;
  76.         }
  77.     }
  78.  
  79.     app.Cleanup();
  80.  
  81.     return msg.wParam;
  82. }
  83.  
  84. APPLICATION::APPLICATION()
  85. {
  86.     m_pDevice = NULL; 
  87.     m_mainWindow = 0;
  88.     m_areaSelect = false;
  89.     srand(GetTickCount());
  90.     m_fps = m_lastFps = 0;
  91.     m_time = GetTickCount();
  92.     m_pLine = NULL;
  93. }
  94.  
  95. HRESULT APPLICATION::Init(HINSTANCE hInstance, int width, int height, bool windowed)
  96. {
  97.     debug.Print("Application initiated");
  98.  
  99.     //Create Window Class
  100.     WNDCLASS wc;
  101.     memset(&wc, 0, sizeof(WNDCLASS));
  102.     wc.style         = CS_HREDRAW | CS_VREDRAW;
  103.     wc.lpfnWndProc   = (WNDPROC)::DefWindowProc; 
  104.     wc.hInstance     = hInstance;
  105.     wc.lpszClassName = "D3DWND";
  106.  
  107.     //Register Class and Create new Window
  108.     RegisterClass(&wc);
  109.     m_mainWindow = CreateWindow("D3DWND", "Example 9.1: Unit Example", WS_EX_TOPMOST, 0, 0, width, height, 0, 0, hInstance, 0); 
  110.     SetCursor(NULL);
  111.     ShowWindow(m_mainWindow, SW_SHOW);
  112.     UpdateWindow(m_mainWindow);
  113.  
  114.     //Create IDirect3D9 Interface
  115.     IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
  116.  
  117.     if(d3d9 == NULL)
  118.     {
  119.         debug.Print("Direct3DCreate9() - FAILED");
  120.         return E_FAIL;
  121.     }
  122.  
  123.     //Check that the Device supports what we need from it
  124.     D3DCAPS9 caps;
  125.     d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
  126.  
  127.     //Hardware Vertex Processing or not?
  128.     int vp = 0;
  129.     if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
  130.         vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  131.     else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  132.  
  133.     //Check vertex & pixelshader versions
  134.     if(caps.VertexShaderVersion < D3DVS_VERSION(2, 0) || caps.PixelShaderVersion < D3DPS_VERSION(2, 0))
  135.     {
  136.         debug.Print("Warning - Your graphic card does not support vertex and pixelshaders version 2.0");
  137.     }
  138.  
  139.     //Set D3DPRESENT_PARAMETERS
  140.     D3DPRESENT_PARAMETERS d3dpp;
  141.     d3dpp.BackBufferWidth            = width;
  142.     d3dpp.BackBufferHeight           = height;
  143.     d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
  144.     d3dpp.BackBufferCount            = 1;
  145.     d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
  146.     d3dpp.MultiSampleQuality         = 0;
  147.     d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
  148.     d3dpp.hDeviceWindow              = m_mainWindow;
  149.     d3dpp.Windowed                   = windowed;
  150.     d3dpp.EnableAutoDepthStencil     = true; 
  151.     d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
  152.     d3dpp.Flags                      = 0;
  153.     d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  154.     d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;
  155.  
  156.     //Create the IDirect3DDevice9
  157.     if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_mainWindow,
  158.                                  vp, &d3dpp, &m_pDevice)))
  159.     {
  160.         debug.Print("Failed to create IDirect3DDevice9");
  161.         return E_FAIL;
  162.     }
  163.  
  164.     //Release IDirect3D9 interface
  165.     d3d9->Release();
  166.  
  167.     D3DXCreateFont(m_pDevice, 18, 0, 0, 1, false,  
  168.                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
  169.                    DEFAULT_PITCH | FF_DONTCARE, "Arial", &m_pFont);
  170.  
  171.     LoadObjectResources(m_pDevice);
  172.     LoadMapObjectResources(m_pDevice);
  173.     LoadUnitResources(m_pDevice);
  174.  
  175.     m_terrain.Init(m_pDevice, INTPOINT(100,100));
  176.  
  177.     m_mouse.InitMouse(m_pDevice, m_mainWindow);
  178.  
  179.     m_camera.Init(m_pDevice);
  180.     m_camera.m_focus = D3DXVECTOR3(50, 10, -50);
  181.     m_camera.m_fov = 0.6f;
  182.     m_camera.m_radius = 50.0f;
  183.  
  184.     D3DXCreateLine(m_pDevice, &m_pLine);
  185.  
  186.     //Set sampler state
  187.     for(int i=0;i<8;i++)
  188.     {
  189.         m_pDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  190.         m_pDevice->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  191.         m_pDevice->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
  192.     }
  193.  
  194.     //Setup shaders
  195.     m_unitVS.Init(m_pDevice, "shaders/lighting.vs", VERTEX_SHADER);
  196.     m_worldHandle = m_unitVS.GetConstant("matW");
  197.     m_viewProjHandle = m_unitVS.GetConstant("matVP");
  198.     m_sunHandle = m_unitVS.GetConstant("DirToSun");
  199.  
  200.     m_unitPS.Init(m_pDevice, "shaders/teamCol.ps", PIXEL_SHADER);
  201.     m_teamColHandle = m_unitPS.GetConstant("tmCol");
  202.  
  203.     AddUnits();
  204.  
  205.     return S_OK;
  206. }
  207.  
  208. HRESULT APPLICATION::Update(float deltaTime)
  209. {        
  210.     //Control camera
  211.     m_camera.Update(m_mouse, m_terrain, deltaTime);
  212.     m_mouse.Update(&m_terrain);
  213.  
  214.     //Update units
  215.     for(int i=0;i<m_units.size();i++)
  216.         m_units[i]->Update(deltaTime);
  217.  
  218.     if(KEYDOWN(VK_SPACE))
  219.     {
  220.         m_terrain.GenerateRandomTerrain(9);
  221.         AddUnits();
  222.     }
  223.     else if(KEYDOWN(VK_ESCAPE))
  224.     {
  225.         Quit();
  226.     }
  227.  
  228.     if(m_mouse.ClickRight())
  229.     {
  230.         m_mouse.DisableInput(300);
  231.  
  232.         //Move units
  233.         for(int i=0;i<m_units.size();i++)
  234.             if(m_units[i]->m_selected)
  235.                 m_units[i]->Goto(m_mouse.m_mappos);
  236.     }
  237.  
  238.     return S_OK;
  239. }    
  240.  
  241. HRESULT APPLICATION::Render()
  242. {
  243.     // Clear the viewport
  244.     m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
  245.  
  246.     //FPS Calculation
  247.     m_fps++;
  248.     if(GetTickCount() - m_time > 1000)
  249.     {
  250.         m_lastFps = m_fps;
  251.         m_fps = 0;
  252.         m_time = GetTickCount();
  253.     }
  254.  
  255.     // Begin the scene 
  256.     if(SUCCEEDED(m_pDevice->BeginScene()))
  257.     {
  258.         m_terrain.Render(m_camera);
  259.  
  260.         D3DXMATRIX world;
  261.         D3DXMatrixIdentity(&world);
  262.  
  263.         m_unitVS.SetMatrix(m_worldHandle, world);
  264.         m_unitVS.SetMatrix(m_viewProjHandle, m_camera.GetViewMatrix() * m_camera.GetProjectionMatrix());
  265.  
  266.         D3DXVECTOR3 sun;
  267.         D3DXVec3Normalize(&sun, &D3DXVECTOR3(0.5f, 1.0f, -0.5));
  268.         m_unitVS.SetVector3(m_sunHandle, sun);
  269.         m_unitPS.SetVector4(m_teamColHandle, D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f));
  270.  
  271.         m_unitVS.Begin();
  272.         m_unitPS.Begin();
  273.  
  274.         for(int i=0;i<m_units.size();i++)
  275.             if(!m_camera.Cull(m_units[i]->GetBoundingBox()))
  276.                 m_units[i]->Render();
  277.  
  278.         m_unitPS.End();
  279.         m_unitVS.End();
  280.  
  281.         //Draw selections
  282.         for(int i=0;i<m_units.size();i++)
  283.             if(!m_camera.Cull(m_units[i]->GetBoundingBox()))
  284.                 m_units[i]->PaintSelected();
  285.  
  286.         Select();
  287.         m_mouse.Paint();
  288.  
  289.         RECT r[] = {{10, 10, 0, 0}, {720, 10, 0, 0}};
  290.         m_pFont->DrawText(NULL, "Space: Randomize Terrain", -1, &r[0], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  291.  
  292.         //FPS
  293.         char number[50];
  294.         std::string text = "FPS: ";
  295.         text += _itoa(m_lastFps, number, 10);
  296.         m_pFont->DrawText(NULL, text.c_str(), -1, &r[1], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  297.  
  298.         // End the scene.
  299.         m_pDevice->EndScene();
  300.         m_pDevice->Present(0, 0, 0, 0);
  301.     }
  302.  
  303.     return S_OK;
  304. }
  305.  
  306. HRESULT APPLICATION::Cleanup()
  307. {
  308.     try
  309.     {
  310.         m_terrain.Release();
  311.  
  312.         m_pLine->Release();
  313.  
  314.         UnloadObjectResources();
  315.         UnloadMapObjectResources();
  316.         UnloadUnitResources();
  317.  
  318.         for(int i=0;i < m_units.size();i++)
  319.             delete m_units[i];
  320.         m_units.clear();
  321.  
  322.         m_pFont->Release();
  323.         m_pDevice->Release();
  324.  
  325.         debug.Print("Application terminated");
  326.     }
  327.     catch(...){}
  328.  
  329.     return S_OK;
  330. }
  331.  
  332. HRESULT APPLICATION::Quit()
  333. {
  334.     ::DestroyWindow(m_mainWindow);
  335.     ::PostQuitMessage(0);
  336.     return S_OK;
  337. }
  338.  
  339. void APPLICATION::AddUnits()
  340. {
  341.     for(int i=0;i<m_units.size();i++)
  342.         if(m_units[i] != NULL)
  343.             delete m_units[i];
  344.     m_units.clear();
  345.  
  346.     //Create random units
  347.     for(int i=0;i<30;i++)
  348.     {
  349.         //Find random walkable position
  350.         INTPOINT mp;
  351.         bool ok = false;
  352.         do
  353.         {
  354.             mp.Set(rand()%m_terrain.m_size.x, rand()%m_terrain.m_size.y);
  355.             MAPTILE *tile = m_terrain.GetTile(mp);            
  356.             if(tile != NULL)ok = tile->m_walkable;
  357.         }
  358.         while(!ok);
  359.  
  360.         m_units.push_back(new UNIT(rand()%3, 0, mp, &m_terrain, m_pDevice));
  361.     }
  362. }
  363.  
  364. int APPLICATION::GetUnit()
  365. {
  366.     //Find closest unit
  367.     int unit = -1;
  368.     float bestDist = 100000.0f;
  369.  
  370.     D3DXMATRIX world;
  371.     D3DXMatrixIdentity(&world);
  372.     m_pDevice->SetTransform(D3DTS_WORLD, &world);
  373.     RAY ray = m_mouse.GetRay();
  374.  
  375.     for(int i=0;i<m_units.size();i++)
  376.     {                    
  377.         float dist = ray.Intersect(m_units[i]->GetBoundingBox());
  378.  
  379.         if(dist >= 0.0f && dist < bestDist)
  380.         {
  381.             unit = i;
  382.             bestDist = dist;
  383.         }
  384.     }
  385.  
  386.     return unit;
  387. }
  388.  
  389. void APPLICATION::Select()
  390. {
  391.     try
  392.     {
  393.         if(m_mouse.ClickLeft())    // If the mouse button is pressed
  394.         {                
  395.             for(int i=0;i<m_units.size();i++)    //Deselect all m_units
  396.                 m_units[i]->m_selected = false;
  397.  
  398.             if(!m_areaSelect)        // If no area selection is in progress
  399.             {    
  400.                 //GetUnit() returns a unit using the mouse ray. If no 
  401.                 // unit is found this function returns -1
  402.                 int unit = GetUnit();
  403.  
  404.                 if(unit > -1)
  405.                     m_units[unit]->m_selected = true;
  406.                 else
  407.                 {
  408.                     m_areaSelect = true;        // if no unit if found,                                             
  409.                     m_startSelect = m_mouse;        // start area selection
  410.                 }
  411.             }
  412.             else                    //Area Selection in progress
  413.             {
  414.                 // Create area rectangle
  415.                 INTPOINT p1 = m_startSelect, p2 = m_mouse;
  416.                 if(p1.x > p2.x){int temp = p2.x;p2.x = p1.x;p1.x = temp;}
  417.                 if(p1.y > p2.y){int temp = p2.y;p2.y = p1.y;p1.y = temp;}
  418.                 RECT selRect = {p1.x, p1.y, p2.x, p2.y};
  419.  
  420.                 //Draw selection rectangle
  421.                 D3DXVECTOR2 box[] = {D3DXVECTOR2(p1.x, p1.y), D3DXVECTOR2(p2.x, p1.y), 
  422.                                      D3DXVECTOR2(p2.x, p2.y), D3DXVECTOR2(p1.x, p2.y), 
  423.                                      D3DXVECTOR2(p1.x, p1.y)};
  424.  
  425.                 m_pLine->SetWidth(1.0f);
  426.                 m_pLine->Begin();
  427.                 m_pLine->Draw(box, 5, 0xffffffff);                
  428.                 m_pLine->End();
  429.  
  430.                 //Select any units inside our rectangle
  431.                 for(int i=0;i<m_units.size();i++)
  432.                 {
  433.                     INTPOINT p = GetScreenPos(m_units[i]->m_position, m_pDevice);
  434.                     if(p.inRect(selRect))m_units[i]->m_selected = true;
  435.                 }
  436.             }
  437.         }
  438.         else if(m_areaSelect)        //Stop area selection
  439.             m_areaSelect = false;
  440.  
  441.     }
  442.     catch(...)
  443.     {
  444.         debug.Print("Error in APPLICATION::Select()");
  445.     }
  446. }